﻿import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import os


# 激活函数及其导数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))


def sigmoid_derivative(x):
    fx = sigmoid(x)
    return fx * (1 - fx)


script_directory = os.path.dirname(os.path.abspath(__file__))

# 初始化参数
np.random.seed(42)
input_size = 2  # 输入层大小（两个输入节点）
output_size = 1  # 输出层大小

# 权重和偏置初始化
W = np.array([[1.0], [-1.0]])
b = np.array([[-0.5]])
# W = np.random.randn(input_size, output_size)
# b = np.random.randn(1, output_size)

# 输入数据（与逻辑的输入）
X = np.array([[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]])
# 输出数据（与逻辑的输出）
y = np.array([[0], [0], [0], [1]])

# 训练参数
learning_rate = 0.1
epochs = 200

frames = 50  # 动图的帧数

# 设置绘图
fig, ax = plt.subplots()
scat_0 = ax.scatter(
    X[y.flatten() == 0, 0], X[y.flatten() == 0, 1], color="red", label="label=0"
)
scat_1 = ax.scatter(
    X[y.flatten() == 1, 0], X[y.flatten() == 1, 1], color="blue", label="label=1"
)
(line,) = ax.plot([], [], "green", label="Decision Boundary")
text = ax.text(-0.5, -0.5, "", fontsize=9)
ax.set_xlim([-0.5, 1.5])
ax.set_ylim([-0.5, 1.5])
ax.set_title("Logical Classification Dataset")
ax.set_xlabel("x1")
ax.set_ylabel("x2")
ax.legend()


# 更新函数
def update(frame):
    global W, b
    for _ in range(epochs // frames):
        # 前向传播
        final_input = np.dot(X, W) + b
        predicted_output = sigmoid(final_input)
        # 计算损失
        loss = y - predicted_output
        # 反向传播
        sd = sigmoid_derivative(final_input)
        output_delta = -loss * sd
        # 更新权重和偏置
        delta_w_l_sum = np.dot(X.T, output_delta)
        W -= learning_rate * delta_w_l_sum
        b -= learning_rate * np.sum(output_delta, axis=0, keepdims=True)
    # 绘制决策边界
    w1, w2 = W[0, 0], W[1, 0]
    b_value = b[0, 0]
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = -(w1 * x1_min + b_value) / w2, -(w1 * x1_max + b_value) / w2
    line.set_data([x1_min, x1_max], [x2_min, x2_max])
    text.set_text(
        f"epoch={frame * (epochs // frames)}, loss={np.mean(np.abs(loss)):.4f}, w1={w1:.4f}, w2={w2:.4f}, b={b_value:.4f}"
    )
    return line, text


# 创建动图
ani = FuncAnimation(fig, update, frames=frames, blit=True)

# 保存动图
ani.save(os.path.join(script_directory, "training_process.gif"), writer="pillow")

plt.show()